//rational.h
#include <string>
#include <cassert>
#include <sstream>
#include <iostream>
using namespace std;
class Rational{
public:
	//constructor
	Rational(int n=0, int d=1);
    Rational(double d); //double to rational
	//arithmatic operations
	Rational add(const Rational& r)const;
	Rational sub(const Rational& r)const;
	Rational mul(const Rational& r)const;
	Rational div(const Rational& r)const;
	//conversion
	string toString()const;
	double toDouble()const;
	Rational toRational(double d)const;
private:
	int nume;  //numerator
	int deno;  //denominator cannot be zero
	//private operation
	static int gcd(int m, int n);
};
//--------------------
//rational.cpp

Rational::Rational(int n, int d)
{
    int g;

	assert(d!=0);

	if(n == 0){
		nume = 0;
		deno = 1;
		return;
	}

	if (d<0)
    {
        d = -d;
        n = -n;
    }

    if (n<0)
        g = gcd(-n, d);
    else
        g = gcd(n, d);

    nume = n/g;
    deno = d/g;
}

Rational::Rational(double val)
{
    const double precision=1.0e-7;
    int d = (int)(1.0/precision);
    int n = (int)(val*d);
    int g;

	assert(d!=0);

	if(n == 0)
    {
		nume = 0;
		deno = 1;
		return;
	}

	if (d<0)
    {
        d = -d;
        n = -n;
    }

    if (n<0)
        g = gcd(-n, d);
    else
        g = gcd(n, d);

    nume = n/g;
    deno = d/g;
}

//arithmatic operations
Rational Rational::add(const Rational& r)const
{
	int d = deno * r.deno;
	int n = deno * r.nume + nume * r.deno;
	return Rational(n, d);
}

Rational Rational::sub(const Rational& r)const
{
	int d = deno * r.deno;
	int n = nume * r.deno - deno * r.nume;
	return Rational(n, d);
}

Rational Rational::mul(const Rational& r)const
{
	return Rational(nume * r.nume, deno * r.deno);
}

Rational Rational::div(const Rational& r)const
{
	return Rational(nume * r.deno, deno * r.nume);
}

//conversion
string Rational::toString()const
{
	ostringstream ostr;

	if(nume == 0)
		ostr << 0;
	else if(deno == 1)
		ostr << nume;
	else
		ostr << nume << "/" << deno;

	return ostr.str();
}

double Rational::toDouble()const
{
	return  static_cast<double>(nume)/deno;
}

int Rational::gcd(int m, int n)
{
    int c = n;
	while (m%n!=0)
	{
		c = m%n;
		m = n;
		n = c;
	}
	return c;
}

int main()
{
	Rational r1; //0
	Rational r2(2, 1);//2/1
	Rational r3(-3, -4); //3/4
	Rational r4(3, -6);
	Rational r5(-3.2);

	cout<<"r1: "<<r1.toString()<<endl;
	cout<<"r2: "<<r2.toString()<<endl;
	cout<<"r3: "<<r3.toString()<<endl;
	cout<<"r4: "<<r4.toString()<<endl;
	cout<<"r5: "<<r5.toString()<<endl;

	cout<<"double value of r1: "<<r1.toDouble()<<endl;
	cout<<"double value of r2: "<<r2.toDouble()<<endl;
	cout<<"double value of r3: "<<r3.toDouble()<<endl;
	cout<<"double value of r4: "<<r4.toDouble()<<endl;

	cout<<"r2+r3: "<<r2.add(r3).toString()<<endl;
	cout<<"r2-r3: "<<r2.sub(r3).toString()<<endl;
	cout<<"r2*r3: "<<r2.mul(r3).toString()<<endl;
	cout<<"r2/r3: "<<r2.div(r3).toString()<<endl;


	cout<<"r4+r3: "<<r4.add(r3).toString()<<endl;
	cout<<"r4-r3: "<<r4.sub(r3).toString()<<endl;
	cout<<"r4*r3: "<<r4.mul(r3).toString()<<endl;
	cout<<"r4/r3: "<<r4.div(r3).toString()<<endl;
}




